// 【测试hex2json】
// var hex = '';
// for (var i = 1; i < 100; i++) {
//     hex += Math.floor(Math.random() * 16).toString(16);
// }
// console.log(hex);
// var json = hexToJson(hex);
// console.log(json);
// var a = 1;
// try {
//     console.log(JSON.stringify(Function('return ' + json)(), null, ' '));
// } catch (e) {
//     console.log(e.stack);
// }


// 【测试aes】
// var a = 'asfdasfs啊afdsfsdf123124,./,/';
// a = '' + aes.enc;
// var m = aes.enc(a, '1234567890123456');
// console.log(m);
// console.log(aes.dec(m, '1234567890123456'));


// 【测试内置函数检测】
// var oldFunction = Function;
// var oldToString = Function.prototype.toString;
// var Function = function(...args) {
//     console.log(...args);
//     return oldFunction(...args);
// };
// Function.prototype = oldFunction.prototype;
// Function.prototype.constructor = Function;
// util.toString = () => {
//     return '123';
// };
// Function.prototype.toString = function() {
//     return 'function ' + this.name + '() { [native code] }';
// };
// ;(function(util) {
//     util.isBuiltin = isBuiltin;
//     util.checkBuiltin = checkBuiltin;

//     // 判断是否非系统内置函数（必须在动态代码中定义，不能放在util中，避免util本身被整体重写并伪造toString）
//     function isBuiltin(foo, name) {

//         // 首先必须是函数
//         if (typeof(foo) !== 'function') return -1;
//         if (!(foo instanceof Function)) return -2;

//         // 系统内置函数转字符串始终为：function foo() { [nativecode] }（不同引擎下空白格式可能不同）
//         var body = foo + '';
//         if (body.length > 100) return 1;
//         if (body.replace(/\s/g, '') != 'function' + (name || foo.name) + '(){[nativecode]}') return 1;

//         // foo.toString或valueOf方法，可能被重写来伪造返回字符串，所以要判断是否为默认函数
//         if (foo.toString !== isBuiltin.toString) return 2;
//         if (foo.valueOf !== isBuiltin.valueOf) return 3;

//         // 内置函数访问caller属性会报异常，而自定义函数一定有值且不可修改（箭头函数除外）
//         // 但箭头函数取不到函数自身this，无法区分是否为重写函数，因此可通过构造临时函数判断
//         try {
//             foo.caller;
//             return 4;
//         } catch (e) {
//         }

//         // Function函数还需加特殊判断
//         if (foo === Function) {
//             if (isBuiltin.constructor !== foo) return 5;
//         }

//         // TODO Array.length等内置属性也可能被重写
//         return 0;
//     }
//     var lookupGetter = isBuiltin.__lookupGetter__;

//     // 检验内置函数是否被重写（若有则抛出异常）
//     // - @target 可为要检测的函数或方法主体，或一个批量列表：[[target, name, [method, ...], ...]
//     // - @name 函数或主体名称
//     // - @method 方法名称（以.开头表示getter属性）
//     function checkBuiltin(target, name, method) {
//         if (name) {
//             var code;
//             if (method) {
//                 if (method.charAt(0) == '.') {
//                     if (!lookupGetter.call(target, method.substr(1))) return;
//                     throw 'Should not overwrite built-in property ' + name + method + '!';
//                 }
//                 if (!lookupGetter.call(target, method)) {
//                     code = isBuiltin(target[method], method);
//                     if (!code) return;
//                 }
//                 name += '.' + method;
//             } else {
//                 code = isBuiltin(target, name);
//                 if (!code) return;
//             }
//             throw 'Should not overwrite built-in function ' + name + '()! [code ' + code + ']';
//         }
//         for (var i in target) {
//             i = target[i];
//             for (var j in i[2]) {
//                 checkBuiltin(i[0], i[1], i[2][j]);
//             }
//         }
//     }

//     // 检验所有用到的内置函数是否被重写，避免重写内置函数加断点攻击
//     var toString = 'toString';
//     var valueOf = 'valueOf';
//     var checkList = [
//         [Function, 'Function', ['']],
//         [parseInt, 'parseInt', ['']],
//         [escape, 'escape', ['']],
//         [unescape, 'unescape', ['']],
//         [encodeURIComponent, 'encodeURIComponent', ['']],
//         [decodeURIComponent, 'decodeURIComponent', ['']],
//         [String, 'String', [
//             'fromCharCode',
//         ]],
//         [Date, 'Date', [
//             'now',
//         ]],
//         [JSON, 'JSON', [
//             'stringify',
//         ]],
//         [Math, 'Math', [
//             'floor',
//             'ceil',
//             'random',
//         ]],
//         [0, 'Number.prototype', [
//             toString,
//             valueOf,
//         ]],
//         ['', 'String.prototype', [
//             toString,
//             valueOf,
//             'charCodeAt',
//             'charAt',
//             'substr',
//             'trim',
//             'indexOf',
//             'replace',
//             'match',
//         ]],
//         [[], 'Array.prototype', [
//             toString,
//             valueOf,
//             'push',
//             'pop',
//             'concat',
//             'slice',
//             'join',
//             '.length',
//         ]],
//         [{}, 'Object.prototype', [
//             toString,
//             valueOf,
//         ]],
//         [isBuiltin, 'Function.prototype', [
//             toString,
//             valueOf,
//             '__lookupGetter__',
//             '.constructor',
//             '.name',
//         ]],
//         [lookupGetter, 'Function.prototype.__lookupGetter__', [
//             'call',
//         ]],
//         [util, 'util', [
//             toString,
//             valueOf,
//         ]],
//     ];
//     try {
//         checkBuiltin(checkList);
//     } catch (e) {
//         console.error(e);
//     }
// })(util);

// console.info(util);
// console.info(Function);
// console.dir(oldFunction, 'old Function', true);
// console.dir(Function, 'new Function', true);
// console.dir(Array, 'Array', true);
// console.dir(Math.abs, 'Math.abs', true);
// console.info(abs = _=>Math.abs(_))
// console.dir(abs, 'my abs', true);


// 【测试jshell】
var code = `
try {
    J$.checkBuiltin(document, 'document', 'write');
} catch (e) {
    return "想作弊？没门儿！\\n" + e;
}
if (false) {
    document.write("不可思议！");
} else {
    document.write("现在我自己也破不了");
}
`;
var tm = Date.now();
var cipher = jshell(code);
console.info('加密用时:', (Date.now() - tm) / 1000, cipher);
// cipher = 'c44ad8eedb011417bcf7c8eeca9a1b0dU2FsdGVkX18BKamWiinCxqr228qjWVIk/T+hmiwsjAF8jgFUEffPbJl0uYNg5Tyreta9z0yg7XEdAAefkPXvplYwXtpsMdLOgen1YK16bH1eHjX9UJ4cjwaF1/TWWhNDlWBT1PSsGDSWJkIezcLHHwFkljOo2AjzrMpwDPOYMyc5LGocnbC2Dv3Q5WxfmFEg+p8tynaG7mSUdin/M7uw3tUIOOlo4oS0NQ9xfgYga7wEsdikzBWlMXLU7yvLlp487RnD+bWYnsN0f3Uucyt5GUmkBKAg9oj6fY5zuBsmySNMBTQB8RUTMAJogcDfu3GNz7fFJI1AsBYVV3vUy3z5oA==';
tm = Date.now();
var result = jshell(cipher);
console.info('解密用时:', (Date.now() - tm) / 1000, result + '');


// 【攻击测试】
// function printStack() {
//     try {
//         null();
//     } catch (e) {
//         console.old_log.apply(null, [e].concat(arguments));
//     }
// }
// counter = 0;
// Window.__defineGetter__('document', function() {
//     debugger;
// });

// document.old_write = document.write;
Object.defineProperty(document, 'write', {
    get() {
        console.old_log(this);
        // debugger;
        return document.old_write;
    }
});
// Object.defineProperty(Function.prototype.__lookupGetter__, 'call', {
//     get() {
//         // console.old_log(this);
//         // debugger;
//         return Object.prototype.__lookupGetter__;
//     }
// });
console.old_log(jshell(cipher));
